package com.framework.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.framework.core.common.enums.StatusEnum;
import com.framework.core.exception.CustomException;
import com.framework.system.entity.SysDept;
import com.framework.system.entity.SysRoleDept;
import com.framework.system.entity.SysUser;
import com.framework.system.entity.dto.SysDeptAddDTO;
import com.framework.system.entity.dto.SysDeptEditDTO;
import com.framework.system.entity.dto.SysDeptQueryDTO;
import com.framework.system.entity.vo.SysDeptListVO;
import com.framework.system.entity.vo.SysDeptVO;
import com.framework.system.mapper.SysDeptMapper;
import com.framework.system.mapper.SysRoleDeptMapper;
import com.framework.system.mapper.SysUserMapper;
import com.framework.system.service.ISysDeptService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 部门表 服务实现类
 * </p>
 *
 * @author Kevin
 * @since 2021-06-10
 */
@Service
@AllArgsConstructor
public class SysDeptServiceImpl implements ISysDeptService {

    private SysDeptMapper sysDeptMapper;

    private SysUserMapper sysUserMapper;

    private SysRoleDeptMapper sysRoleDeptMapper;

    @Override
    public Page<SysDeptListVO> selectPage(Page reqPage, SysDeptQueryDTO req) {
        LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(Objects.nonNull(req.getParentId()), SysDept::getParentId, req.getParentId());
        queryWrapper.like(StrUtil.isNotBlank(req.getDeptName()), SysDept::getDeptName, req.getDeptName());
        queryWrapper.like(StrUtil.isNotBlank(req.getDeptFullname()), SysDept::getDeptFullname, req.getDeptFullname());
        queryWrapper.orderByAsc(SysDept::getSort);
        Page<SysDept> page = sysDeptMapper.selectPage(reqPage, queryWrapper);
        Page<SysDeptListVO> voPage = BeanUtil.copyProperties(page, Page.class);
        voPage.setRecords(BeanUtil.copyToList(page.getRecords(), SysDeptListVO.class));
        return voPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysDeptAddDTO req) {
        if (!this.checkUniqueDeptName(req.getDeptName(), null)) {
            throw new CustomException("部门名称已存在");
        }
        SysDept entity = BeanUtil.copyProperties(req, SysDept.class);
        if (Objects.isNull(req.getParentId())) {
            entity.setParentId(0L);
            entity.setAncestors(entity.getParentId().toString());
        } else {
            SysDept parent = sysDeptMapper.selectById(req.getParentId());
            entity.setAncestors(parent.getAncestors() + "," + entity.getParentId().toString());
        }
        sysDeptMapper.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysDeptEditDTO req) {
        if (!this.checkUniqueDeptName(req.getDeptName(), req.getId())) {
            throw new CustomException("部门名称已存在");
        }
        if (req.getStatus().equals(StatusEnum.NO.getCode()) &&
                sysDeptMapper.selectList(Wrappers.lambdaQuery(SysDept.class)
                        .eq(SysDept::getStatus, StatusEnum.YES.getCode())
                        .apply("find_in_set({0}, ancestors)", req.getId())).size() > 0) {
            throw new CustomException("该部门存在未停用的下级部门");
        }
        SysDept entity = BeanUtil.copyProperties(req, SysDept.class);
        if (Objects.isNull(req.getParentId())) {
            entity.setParentId(0L);
            entity.setAncestors(entity.getParentId().toString());
        } else {
            SysDept parent = sysDeptMapper.selectById(req.getParentId());
            entity.setAncestors(parent.getAncestors() + "," + entity.getParentId().toString());
        }
        SysDept sysDept = sysDeptMapper.selectById(req.getId());
        // 更新子节点的祖级列表
        List<SysDept> sysDeptList = sysDeptMapper.selectList(Wrappers.lambdaQuery(SysDept.class)
                .apply("find_in_set({0}, ancestors)", req.getId()));
        sysDeptList.forEach(item -> {
            item.setAncestors(item.getAncestors().replaceFirst(sysDept.getAncestors(), entity.getAncestors()));
        });
        sysDeptMapper.updateById(entity);
        // 启用该部门，则启用该部门的所有上级部门
        List<String> parentList = Arrays.asList(entity.getAncestors().split(","));
        parentList.stream().forEach(item -> {
            SysDept sysDeptTemp = new SysDept();
            sysDeptTemp.setId(Long.parseLong(item));
            sysDeptTemp.setStatus(StatusEnum.YES.getCode());
            sysDeptMapper.updateById(sysDeptTemp);
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(String ids) {
        List<String> idList = Arrays.asList(ids.split(","));
        idList.forEach(item -> {
            SysDept sysDept = sysDeptMapper.selectById(item);
            SysDept sysDeptChild = sysDeptMapper.selectOne(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getParentId, item));
            if (Objects.nonNull(sysDeptChild)) {
                throw new CustomException(String.format("部门【%s】存在下级部门，无法删除", sysDept.getDeptName()));
            }
            SysUser sysUser = sysUserMapper.selectOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getDeptId, item));
            if (Objects.nonNull(sysUser)) {
                throw new CustomException(String.format("部门【%s】存在用户，无法删除", sysDept.getDeptName()));
            }
            SysRoleDept sysRoleDept = sysRoleDeptMapper.selectOne(Wrappers.lambdaQuery(SysRoleDept.class).eq(SysRoleDept::getDeptId, item));
            if (Objects.nonNull(sysRoleDept)) {
                throw new CustomException(String.format("部门【%s】已被使用，无法删除", sysDept.getDeptName()));
            }
        });
        idList.stream().forEach(item -> {
            sysDeptMapper.deleteById(item);
        });
    }

    @Override
    public SysDeptVO view(String id) {
        SysDept entity = sysDeptMapper.selectById(id);
        return BeanUtil.copyProperties(entity, SysDeptVO.class);
    }

    @Override
    public List<Tree<String>> listDeptTree() {
        List<SysDept> sysDeptList = sysDeptMapper.selectList(Wrappers.emptyWrapper());
        List treeNodeList = sysDeptList.stream().map(item -> {
            TreeNode treeNode = new TreeNode();
            treeNode.setId(item.getId().toString());
            treeNode.setName(item.getDeptName());
            treeNode.setParentId(item.getParentId().toString());
            treeNode.setWeight(item.getSort());
            return treeNode;
        }).collect(Collectors.toList());
        List<Tree<String>> treeList = TreeUtil.build(treeNodeList, "0");
        return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
    }

    @Override
    public List<Tree<String>> selectDeptTreeAndExcludeNode(String nodeId) {
        List<SysDept> sysDeptList = sysDeptMapper.selectList(Wrappers.emptyWrapper());
        if (StrUtil.isNotBlank(nodeId)) {
            Iterator<SysDept> it = sysDeptList.iterator();
            while (it.hasNext()) {
                SysDept sysDept = it.next();
                if (sysDept.getId().toString().equals(nodeId) || Arrays.asList(sysDept.getAncestors().split(",")).contains(nodeId)) {
                    it.remove();
                }
            }
        }
        List treeNodeList = sysDeptList.stream().map(item -> {
            TreeNode treeNode = new TreeNode();
            treeNode.setId(item.getId().toString());
            treeNode.setName(item.getDeptName());
            treeNode.setParentId(item.getParentId().toString());
            treeNode.setWeight(item.getSort());
            return treeNode;
        }).collect(Collectors.toList());
        List<Tree<String>> treeList = TreeUtil.build(treeNodeList, "0");
        return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
    }

    @Override
    public List<Tree<String>> selectDeptTree() {
        List<SysDept> sysDeptList = sysDeptMapper.selectList(Wrappers.emptyWrapper());
        List treeNodeList = sysDeptList.stream().map(item -> {
            TreeNode treeNode = new TreeNode();
            treeNode.setId(item.getId().toString());
            treeNode.setName(item.getDeptName());
            treeNode.setParentId(item.getParentId().toString());
            treeNode.setWeight(item.getSort());
            return treeNode;
        }).collect(Collectors.toList());
        List<Tree<String>> treeList = TreeUtil.build(treeNodeList, "0");
        return CollectionUtils.isEmpty(treeList) ? new ArrayList() : treeList;
    }

    private Boolean checkUniqueDeptName(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysDept entity = sysDeptMapper.selectOne(Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getDeptName, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

}
